#[cfg(test)]
pub mod test_trait {
	/*
Trait
.Trait告诉Rust编译器：
    ﹣某种类型具有哪些并且可以与其它类型共享的功能
Trait：抽象的定义共享行为
·Trait bounds（约束）：泛型类型参数指定为实现了特定行为的类型.
Trait 与其它语言的接口（interface）类似，但有些区别。
	 */

     /* 定义一个 Trait
.Trait的定义：把方法签名放在一起，来定义实现某种目的所必需的一组行为。
    -trait 可以有多个方法：每个方法签名占一行，以；结尾
    - 只有方法签名，没有具体实现
    ﹣关键字：trait
    ﹣实现该 trait 的类型必须提供具体的方法实现
 */

 /*在类型上实现 trait
．与为类型实现方法类似。
。不同之处：
    - impl Xxxx for Tweet (...}
    ﹣在impl的块里，需要对Trait里的方法签名进行具体的实现
  */

use std::fmt::{Debug, Display};

      /* 实现trait 的约束 
．可以在某个类型上实现某个 trait 的前提条件是：
    ﹣这个类型 或这个 trait 是在本地crate 里定义的
．无法为外部类型来实现外部的trait:
    ﹣这个限制是程序属性的一部分（也就是一致性）。
    ﹣更具体地说是孤儿规则：之所以这样命名是因为父类型不存在。
    ﹣此规则确保其他人的代码不能破坏您的代码，反之亦然。
    ﹣如果没有这个规则，两个crate可以为同一类型实现同一个trait,Rust就不知道应该使用哪个实现了。
     */
    #[test]
    fn trait01() {
        let zhang3 = Score{
            yuwen: 78,
            yingyu: 99
        };
        println!("shang san score total is {}", zhang3.sum2());
        let p1 = Assets {
            house: 200,
            money: 1_000_0000,
        };
        print_sum("p1 sum", p1);

        let p2 = Assets {
            house: 2000,
            money: 1_000_0000,
        };
    /*
Trait 作为参数 
.impl Trait 语法：适用于简单情况
.Trait bound 语法：可用于复杂情况
    -impl Trait 语法是Trait bound 的语法糖
．使用＋指定多个 Trait bound 
.Trait bound 使用where 子句
    ﹣在方法签名后指定 where 子句
*/
        print_sum2("p2 sum", &p2);
        print_sum3("p2 sum", &p2, &p2);
        print_sum4("p2 sum", &p2, 24);
        print_sum5("p2 sum", &p2, 12);
    }
    pub fn print_sum(str: &str, p: impl Sum) {
        println!("=== print_sum >>>{} = {}", str, p.sum());
    }
    pub fn print_sum2<T: Sum>(str: &str, p: &T) {
        println!("=== print_sum2 >>>{} = {}", str, p.sum2());
    }
    pub fn print_sum3<T: Sum + Display>(str: &str, p1: &T, p2: &T) {
        println!("=== print_sum3 >>>{} = {}", str, p1.sum2());
    }
    pub fn print_sum4<T: Sum + Display, U: Clone + Debug>(str: &str,t: &T, u: U) -> String {
        println!("=== print_sum4 >>>{} = {}", str, t.sum2());
        String::from("value")
    }
    pub fn print_sum5<T, U>(str: &str,t: &T, u: U) -> String 
    where 
        T: Sum + Display,
        U: Clone + Debug,
    {
        println!("=== print_sum5 >>>{} = {}", str, t.sum2());
        String::from("value")
    }

/* 实现Trait作为返回类型
.impl Trait 语法
．注意：impl Trait 只能返回确定的同一种类型，返回可能不同类型的代码会报错
 */

    #[test]
    fn trait02() {
        let p1 = create_score(89, 119);
        print_sum("sc", p1);
    }

    pub fn create_score(yuwen: u32, yingyu: u32) -> impl Sum {
        Score{ yuwen, yingyu }
    }

    pub trait Sum {
        fn sum(&self) -> u32 {
            0
        }
        fn sum2(&self) -> u32;
    }

    pub struct Score {
        pub yuwen: u32,
        pub yingyu: u32,
    }

    impl Sum for Score {
        fn sum2(&self) -> u32 {
            self.yingyu + self.yuwen
        }
    }

    pub struct Assets {
        pub house: u32,
        pub money: u32,
    }

    impl Sum for Assets {
        fn sum2(&self) -> u32 {
            self.house + self.money
        }
    }

    impl Display for Assets {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            if 1 < 2 {
                Ok(())
            } else {
                Err(std::fmt::Error)
            }
        }
    }

    /* Trait Bound 修复largest函数 */
    #[test]
    fn trait03() {
        let arr = [1, 2, 4, 9, 1, 5, 2];
		let large = largest(&arr);
		println!("large = {}", large);

		let arr2 = vec![1, 2, 4, 9, 11, 5, 2];
		let large = largest2(&arr2);
		println!("large = {}", large);
    }

    fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
		let mut n = list[0];
		for &i in list {
            if n < i {
                n = i;
            }
		}
		n
	}

    fn largest2<T: PartialOrd + Copy>(list: &[T]) -> T {
        let mut n = list[0].clone();
		for i in list {
            if &n < i { // std::cmp::PartialOrd
                n = i.clone();
            }
		}
		n
	}

    /*使用Trait Bound有条件的实现方法
    ．在使用泛型类型参数的impl块上使用Trait bound，我们可以有条件的为实现了特定Trait的类型来实现方法
    ．也可以为实现了其它 Trait 的任意类型有条件的实现某个Trait
    ．为满足Trait Bound的所有类型上实现Trait 叫做覆盖实现（blanket implementations)
    */
    #[test]
    fn trait04() {
        let s = String::from("value");
        // impl<T: fmt::Display + ?Sized> ToString for T {
        s.to_string();
    }

    struct Pair<T> {
        x: T,
        y: T,
    }

    impl <T> Pair<T> {
        fn new(x: T, y: T) -> Self {
            Self {x, y}
        }
    }

    impl <T: Display + PartialOrd> Pair<T> {
        fn cmp_display(&self) {
            if self.x > self.y {
                println!("big x = {}", self.x);
            } else {
                println!("big y = {}", self.y);
            }

        }
    }


}
